/*
 *  $Id$
 *  Copyright [2010] [Panxiaobo] 
 *  Licensed under the Apache License, Version 2.0 (the "License"); 
 *  you may not use this file except in compliance with the License. 
 *  You may obtain a copy of the License at
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 *  Unless required by applicable law or agreed to in writing, software 
 *  distributed under the License is distributed on an "AS IS" BASIS, 
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 *  See the License for the specific language governing permissions and 
 *  limitations under the License. 
 */
package pxb.openid.util;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec;
import javax.crypto.spec.DHPublicKeySpec;

import pxb.openid.OpenIdException;

/**
 * DH算法的工具类
 * 
 * @author Panxiaobo
 * 
 */
public class Dh {
    /**
     * 根据p,和g生成密钥对
     * 
     * @param p
     * @param g
     * @return
     */
    public static KeyPair generateKeyPair(BigInteger p, BigInteger g) {
        return generateKeyPair(new DHParameterSpec(p, g));
    }

    public static KeyPair generateKeyPair(DHParameterSpec params) {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH");
            keyPairGen.initialize(params);
            return keyPairGen.generateKeyPair();
        } catch (Exception e) {
            throw new OpenIdException("生成密钥对时发生异常", e);
        }
    }

    /**
     * 生成密钥对
     * 
     * @param size
     *            密钥长度
     * @return
     */
    public static KeyPair generateKeyPair(int size) {
        KeyPairGenerator keyPairGen;
        try {
            keyPairGen = KeyPairGenerator.getInstance("DH");
        } catch (NoSuchAlgorithmException e) {
            throw new OpenIdException("没有算法: DH", e);
        }
        keyPairGen.initialize(size);
        return keyPairGen.generateKeyPair();
    }

    /**
     * 恢复私钥
     * 
     * @param p
     * @param g
     * @param x
     * @return
     */
    public static DHPrivateKey restorePrivateKey(BigInteger p, BigInteger g, BigInteger x) {
        try {
            KeyFactory keyFac = KeyFactory.getInstance("DH");
            PrivateKey privateKey = keyFac.generatePrivate(new DHPrivateKeySpec(x, p, g));
            return (DHPrivateKey) privateKey;
        } catch (Exception e) {
            throw new OpenIdException("恢复私钥时发生异常", e);
        }
    }

    /**
     * 恢复公钥
     * 
     * @param p
     * @param g
     * @param y
     * @return
     */
    public static DHPublicKey restorePublicKey(BigInteger p, BigInteger g, BigInteger y) {
        try {
            KeyFactory keyFac = KeyFactory.getInstance("DH");
            PublicKey PublicKey = keyFac.generatePublic(new DHPublicKeySpec(y, p, g));
            return (DHPublicKey) PublicKey;
        } catch (Exception e) {
            throw new OpenIdException("恢复公钥时发生异常", e);
        }
    }

    public static BigInteger shared(DHPrivateKey x, BigInteger y) {
        return y.modPow(x.getX(), x.getParams().getP());
        // DHPublicKey providerPublicKey = Dh.restorePublicKey(x.getParams(), y);
        // try {
        // KeyAgreement keyAgree = KeyAgreement.getInstance("DH");
        // keyAgree.init(x);
        // keyAgree.doPhase(providerPublicKey, true);
        // return keyAgree.generateSecret();
        // } catch (Exception e) {
        // throw new RuntimeException(e);
        // }
    }

    public static DHPublicKey restorePublicKey(DHParameterSpec params, BigInteger y) {
        return restorePublicKey(params.getP(), params.getG(), y);
    }

}